//使用变量定义三种状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
//定义一个函数来处理.then返回的promise
//需要使用到resolve,reject方法 所以传递过来
function resolvePromise (promise,x,resolve,reject) {
  if(x === promise) {
    reject (TypeError('cycle'))
    //null 的数据类型也是object
  }else if((typeof x === 'object' && x !== null) || typeof x === 'function') {
    let called = false
    try {
      const then = x.then
      if(typeof then === 'function') {
        const resolvePromiseThen = y => {
          if(called) return
          called = true
          resolvePromiseThen(promise,y,resolve,reject)
        }
        const rejectPromiseThen = r => {
          if(called) return
          called = true
          reject(r)
        }
        then.call(x,resolvePromiseThen,rejectPromiseThen)
      } else {
        resolve(x)
      }
    } catch (error) {
      if(called) return
      called = true
      reject(error)
    }
  }else {
    resolve(x)
  }
}
//1.写一个构造函数 搭建基本结构
class BasicPromise {
  //2.函数执行器 定义 resolve 和 reject方法
  constructor(executor) {
    //定义初始状态 初始化值
    this.state = PENDING
    this.value = undefined
    this.reason = undefined
    //如果.then里面是异步函数 需要先将代码存储起来然后等待 resolve 或者 reject 执行完毕拿到结果后再去执行
    this.onFulfilledCallbacks = []
    this.onRejectedCallbacks = []
    //resolve方法
    const resolve = value => {
      //当触发resolve方法时 判断状态是否在pending 如果在 就需要改变状态至 FULFILLED
      if(this.state === PENDING) {
        this.state = FULFILLED
        this.value = value
        //因为是数组 所以需要去循环依次执行
        this.onFulfilledCallbacks && this.onFulfilledCallbacks.forEach(onFulfilled => onFulfilled(value))
      }
    }
    //reject方法
    const reject = reason => {
      //当触发reject方法时 判断状态是否在pending 如果在 就需要改变状态至 REJECTED
      if(this.state === PENDING) {
        this.state = REJECTED
        this.reason = reason
        //因为是数组 所以需要去循环依次执行
        this.onRejectedCallbacks && this.onRejectedCallbacks.forEach(onRejected => onRejected(reason))
      }
    }
    //错误的抛出
    try {
      executor(resolve,reject)
    } catch (error) {
      throw error
    }
  }
  //promise的.then方法 接收两个参数
  then(onFulfilled,onRejected) {
    //解决.then方法返回的是一个promise对象
    const promise2 = new BasicPromise((resolve,reject) => {
        //同步代码
        //根据状态来判断 要执行的函数 如果状态为FULFILLED 则执行onFulfilled函数 并传入对应的value
        //保证promise执行是异步 settimeout
      if(this.state === FULFILLED) {
          //需要去判断是否是一个函数 如果是 则继续执行返回promise2 如果不是 就返回与promise1相同的值
        if(typeof onFulfilled === 'function') {
          setTimeout(() => {
          //需要去捕获错误
              try {
                const x = onFulfilled(this.value)
                resolvePromise(promise2,x,resolve,reject)
              } catch (error) {
                reject(error)
              }  
          }, 0)
        } else {
          resolve(this.value)
        }
        //同步代码
        //根据状态来判断 要执行的函数 如果状态为REJECTED 则执行onRejected函数 并传入对应的reason
        //保证promise执行是异步 settimeout
      }else if(this.state === REJECTED) {
        //需要去判断是否是一个函数 如果是 则继续执行返回promise2 如果不是 就返回与promise1相同的拒因
        if(typeof onRejected === 'function') {
          setTimeout(() => {
            //需要去捕获错误
              try {
                const x = onRejected(this.reason)
                resolvePromise(promise2,x,resolve,reject)
              } catch (error) {
                reject(error)
              }
          }, 0)
        } else {
          reject(this.reason)
        }
      }else {
        //异步代码
        //根据状态来判断 要执行的函数 如果状态为PENDING 则判断对应的resolve 或者 reject 并将代码存储起来
        //保证promise执行是异步 settimeout
        //要保证.then方法的多次调用 所以需要去使用数组依次存储
        this.onFulfilledCallbacks.push(value => setTimeout(()=> {
          //当这个执行的时候 意味着promise1已经被解决
          if(typeof onFulfilled === 'function') {
              try {
                const x = onFulfilled(value)
                resolvePromise(promise2,x,resolve,reject)
              } catch (error) {
                reject(error)
              }  
          }else {
            resolve(value)
          }
            
        },0))
          //要保证.then方法的多次调用 所以需要去使用数组依次存储
        this.onRejectedCallbacks.push(reason => setTimeout(()=> {
          //当这个执行的时候 意味着promise1已经被拒绝
          if(typeof onRejected === 'function') {
            try {
                const x = onRejected(reason)
                resolvePromise(promise2,x,resolve,reject)
              } catch (error) {
                reject(error)
              }
          } else {
            reject(reason)
          } 
        },0))
      }
    })
    //调用.then方法返回一个promise对象
    return promise2    
  }
}
